package cn.fboost.mtos.service.impl;

import cn.fboost.mtos.dto.Response;
import cn.fboost.mtos.dto.internal.Session;
import cn.fboost.mtos.dto.request.*;
import cn.fboost.mtos.dto.response.OrderDetailResponse;
import cn.fboost.mtos.dto.response.PageResponse;
import cn.fboost.mtos.entity.Order;
import cn.fboost.mtos.entity.Product;
import cn.fboost.mtos.entity.ProductRate;
import cn.fboost.mtos.entity.User;
import cn.fboost.mtos.mapper.OrderMapper;
import cn.fboost.mtos.mapper.ProductMapper;
import cn.fboost.mtos.mapper.ProductRateMapper;
import cn.fboost.mtos.service.OrderService;
import cn.fboost.mtos.task.ProductTask;
import cn.fboost.mtos.util.ConfigUtil;
import cn.fboost.mtos.util.ContextHolderUtil;
import cn.fboost.mtos.util.SnowflakeIdUtil;
import cn.fboost.mtos.util.WeChatUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    private final ConfigUtil configUtil;
    private final WeChatUtil weChatUtil;
    private final OrderMapper orderMapper;
    private final ProductMapper productMapper;
    private final ProductRateMapper productRateMapper;
    private final ProductTask productTask;

    private final SnowflakeIdUtil snowflakeIdUtil;

    public OrderServiceImpl(ConfigUtil configUtil, WeChatUtil weChatUtil, OrderMapper orderMapper,
                            ProductMapper productMapper, ProductRateMapper productRateMapper, ProductTask productTask,
                            SnowflakeIdUtil snowflakeIdUtil) {
        this.configUtil = configUtil;
        this.weChatUtil = weChatUtil;
        this.orderMapper = orderMapper;
        this.productMapper = productMapper;
        this.productRateMapper = productRateMapper;
        this.productTask = productTask;
        this.snowflakeIdUtil = snowflakeIdUtil;
    }

    @Override
    public Response getDeliveryFee() {
        return Response.builder()
                .success()
                .msg("获取成功")
                .data(configUtil.getDouble("order.delivery.fee"))
                .build();
    }

    @Override
    public Response list(OrderListRequest request) {
        Session session = ContextHolderUtil.getCurrentSession();
        // 普通用户只能查看自己的订单
        if (session.getRole() == Session.Role.USER) {
            request.setUserId(session.getId());
            request.setProductId(null);
        }

        // 构建查询条件实体并查询
        Order order = new Order();
        order.setUserId(request.getUserId());
        order.setProductId(request.getProductId());
        order.setStatus(request.getStatus());

        int count = orderMapper.count(order);
        List<Order> list = orderMapper.listBy(order, request.getPagination().getPageOffset());

        PageResponse resp = new PageResponse();
        resp.setTotal(count);
        resp.setList(list);

        return Response.builder().success().msg("获取成功").data(resp).build();
    }

    @Override
    public Response detail(OrderDetailRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());

        Session session = ContextHolderUtil.getCurrentSession();
        // 普通用户只能查看自己的订单
        if (session.getRole() == Session.Role.USER && !Objects.equals(session.getId(), order.getUserId())) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 构建订单详情实体
        OrderDetailResponse response = (OrderDetailResponse) order;
        response.setProduct(productMapper.findById(order.getProductId()));
        return Response.builder().success().msg("获取成功").data(response).build();
    }

    @Override
    public Response create(OrderCreateRequest request) {
        // 检查商品是否存在
        Product product = productMapper.findById(request.getProductId());
        if (product == null || product.getOffShelf()) {
            return Response.builder().failure().msg("商品不存在").build();
        }

        if (product.getSellOut()) {
            return Response.builder().failure().msg("非常抱歉，该商品已售罄，再看看别的吧").build();
        }

        // 从会话中获取用户信息
        Session session = ContextHolderUtil.getCurrentSession();
        User user = session.getUser();

        // 获取配送费
        double deliveryFee = configUtil.getDouble("order.delivery.fee");

        // 使用雪花算法生成订单号
        String tradeNo = String.valueOf(snowflakeIdUtil.nextId());

        // 构建订单实体并保存
        Order order = new Order();
        order.setUserId(user.getId());
        order.setProductId(product.getId());
        order.setTradeNo(tradeNo);
        order.setDescription(product.getName() + " *" + request.getQuantity());
        order.setQuantity(request.getQuantity());
        order.setRemark(request.getRemark());
        order.setReceiverName(request.getReceiverName());
        order.setReceiverTelephone(request.getReceiverTelephone());
        order.setReceiverAddress(request.getReceiverAddress());
        order.setAmount(product.getPrice() * request.getQuantity() + deliveryFee);
        order.setStatus(Order.Status.UNPAID);
        order.setCreateTime(new Date());
        if (orderMapper.create(order) == 0) {
            log.error("订单创建失败，order={}", order);
            return Response.builder().success().msg("订单创建失败").build();
        }

        return Response.builder().success().msg("订单创建成功").data(order.getTradeNo()).build();
    }

    @Override
    public Response pay(OrderPayRequest request) {
        // 检查订单是否存在
        Session session = ContextHolderUtil.getCurrentSession();
        Order order = orderMapper.findByTradeNo(request.getTradeNo());
        if (order == null || !Objects.equals(order.getUserId(), session.getId())) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        Config payConfig = weChatUtil.getPayConfig();
        if (payConfig == null) {
            log.error("订单创建失败，创建微信支付内建配置失败");
            return Response.builder().failure().msg("下单失败，请稍候再试").build();
        }

        // 订单金额转换为分
        Amount amount = new Amount();
        amount.setTotal((int) (order.getAmount() * 100));

        // 构建订单预支付请求
        JsapiServiceExtension jsapiService = new JsapiServiceExtension.Builder().config(payConfig).build();
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setAmount(amount);
        prepayRequest.setMchid(configUtil.getString("wechat.pay.merchant-id"));
        prepayRequest.setAppid(configUtil.getString("wechat.pay.appid"));
        prepayRequest.setNotifyUrl(configUtil.getString("wechat.pay.notify-url"));
        prepayRequest.setOutTradeNo(order.getTradeNo());
        prepayRequest.setDescription(order.getDescription());

        // 设置支付用户信息
        Payer payer = new Payer();
        payer.setOpenid(session.getUser().getWechatOpenId());
        prepayRequest.setPayer(payer);

        // 发送预支付请求
        try {
            PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(prepayRequest);
            return Response.builder().success().msg("请求成功").data(response).build();
        } catch (HttpException | MalformedMessageException | ServiceException | ValidationException e) {
            log.error("订单支付失败，创建微信支付预支付失败", e);
            return Response.builder().failure().msg("预支付请求发送失败，请稍候再试").build();
        }
    }

    @Override
    @Transactional
    public Response cancel(OrderCancelRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());

        Session session = ContextHolderUtil.getCurrentSession();
        if (order == null || !Objects.equals(order.getUserId(), session.getId())) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (Arrays.binarySearch(new int[]{
                Order.Status.SHIPPING,
                Order.Status.FINISHED,
                Order.Status.CANCELED,
                Order.Status.REFUNDING,
                Order.Status.REFUNDED,
                Order.Status.REFUND_FAILED,
                Order.Status.CLOSED
        }, order.getStatus()) >= 0) {
            return Response.builder().failure().msg("订单取消失败").build();
        }

        // 构建更新实体
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(Order.Status.CANCELED);
        update.setUpdateTime(new Date());
        if (orderMapper.update(update) == 0) {
            log.error("订单取消失败，order={}", order);
            return Response.builder().failure().msg("订单取消失败").build();
        }

        // 该订单已经支付，需要退款
        if (order.getStatus() != Order.Status.UNPAID) {
            boolean requestFail = false;
            try {
                Refund refundResp = requestWechatPayRefund(order, order.getAmount(), "用户取消订单");
                if (refundResp.getStatus().equals(Status.ABNORMAL)) {
                    log.error("用户操作微信退款请求失败，响应提示退款状态异常，order={}", order);
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Response.builder().failure().msg("订单取消失败，请联系客服处理").build();
                }
            } catch (HttpException | MalformedMessageException | ServiceException | ValidationException e) {
                requestFail = true;
                log.error("微信退款请求失败", e);
            } finally {
                // 退款失败，回滚订单状态
                if (requestFail) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                }
            }

            if (requestFail) {
                return Response.builder().failure().msg("订单取消失败").build();
            }

            return Response.builder().success().msg("订单已发起退款").build();
        }

        return Response.builder().success().msg("订单已取消").build();
    }

    @Override
    public Response confirm(OrderConfirmRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());
        if (order == null) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (order.getStatus() != Order.Status.PAID) {
            return Response.builder().failure().msg("当前订单无法进行确认操作").build();
        }

        // 构建更新实体
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(Order.Status.CONFIRMED);
        update.setUpdateTime(new Date());
        if (orderMapper.update(update) == 0) {
            log.error("订单确认失败，order={}", order);
            return Response.builder().failure().msg("订单确认失败").build();
        }

        productTask.incrSales(order.getProductId(), order.getQuantity());
        return Response.builder().success().msg("订单已确认").build();
    }

    @Override
    public Response rate(OrderRateRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());
        Session session = ContextHolderUtil.getCurrentSession();
        if (order == null || !Objects.equals(order.getUserId(), session.getId())) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (order.getStatus() != Order.Status.FINISHED) {
            return Response.builder().failure().msg("当前订单无法进行评价").build();
        }

        // 判断该订单是否已经评价过
        ProductRate productRate = productRateMapper.findByOrderId(order.getId());
        if (productRate != null) {
            return Response.builder().failure().msg("当前订单已评价").build();
        }

        // 构建评价实体
        productRate = new ProductRate();
        productRate.setOrderId(order.getId());
        productRate.setProductId(order.getProductId());
        productRate.setUserId(session.getId());
        productRate.setRate(request.getRate());
        productRate.setComment(request.getComment());
        productRate.setCreateTime(new Date());
        if (productRateMapper.create(productRate) == 0) {
            log.error("订单评价失败，order={}", order);
            return Response.builder().failure().msg("评价失败，请稍候重试").build();
        }

        return Response.builder().success().msg("评价成功").build();
    }

    @Override
    public Response ship(OrderShipRequest request) {
        Order order = orderMapper.findById(request.getOrderId());
        if (order == null) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (order.getStatus() != Order.Status.CONFIRMED) {
            return Response.builder().failure().msg("当前订单无法进行配送操作").build();
        }

        // 构建更新实体
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(Order.Status.SHIPPING);
        update.setShipper(request.getShipperName());
        update.setShipperTelephone(request.getShipperTelephone());
        update.setUpdateTime(new Date());
        if (orderMapper.update(update) == 0) {
            log.error("订单配送失败，order={}", order);
            return Response.builder().failure().msg("操作失败，请稍候再试").build();
        }

        return Response.builder().success().msg("订单状态已更改").build();
    }

    @Override
    @Transactional
    public Response refund(OrderRefundRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());
        if (order == null) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (Arrays.binarySearch(new int[]{
                Order.Status.UNPAID,
                Order.Status.CANCELED,
                Order.Status.REFUNDING,
                Order.Status.REFUNDED,
                Order.Status.CLOSED
        }, order.getStatus()) >= 0) {
            return Response.builder().failure().msg("当前订单无法进行退款操作").build();
        }

        // 构建更新实体
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(Order.Status.REFUNDING);
        update.setUpdateTime(new Date());
        if (orderMapper.update(update) == 0) {
            log.error("订单退款失败，order={}", order);
            return Response.builder().failure().msg("退款失败，请稍候再试").build();
        }

        // 发送退款请求
        boolean requestFail = false;
        try {
            Refund refundResp = requestWechatPayRefund(order, request.getRefundAmount(), "商家退款");
            if (refundResp.getStatus().equals(Status.ABNORMAL)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Response.builder().failure().msg("退款失败，响应状态返回异常，请前往商户平台手动处理").build();
            }
        } catch (HttpException | MalformedMessageException | ServiceException | ValidationException e) {
            requestFail = true;
            log.error("微信退款请求失败", e);
        } finally {
            // 退款失败，回滚订单状态
            if (requestFail) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        }

        if (requestFail) {
            return Response.builder().failure().msg("退款失败，请稍候再试").build();
        }
        return Response.builder().success().msg("订单已发起退款").build();
    }

    @Override
    public Response finish(OrderFinishRequest request) {
        Order order = orderMapper.findByTradeNo(request.getTradeNo());
        Session session = ContextHolderUtil.getCurrentSession();
        if (order == null || !Objects.equals(order.getUserId(), session.getId())) {
            return Response.builder().failure().msg("订单不存在").build();
        }

        // 订单状态检查
        if (order.getStatus() != Order.Status.SHIPPING) {
            return Response.builder().failure().msg("当前订单无法进行确认操作").build();
        }

        // 构建更新实体
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(Order.Status.FINISHED);
        update.setUpdateTime(new Date());
        if (orderMapper.update(update) == 0) {
            log.error("订单确认收货失败，order={}", order);
            return Response.builder().failure().msg("订单确认收货失败").build();
        }

        return Response.builder().success().msg("订单已完成").build();
    }

    @Override
    public Response paidOrderCount(Integer status) {
        return Response.builder().success().msg("获取成功").data(orderMapper.countByStatus(status)).build();
    }

    private Refund requestWechatPayRefund(Order order, double refundAmount, String reason) {
        RefundService refundService = new RefundService.Builder().config(weChatUtil.getPayConfig()).build();
        CreateRequest refundRequest = new CreateRequest();

        AmountReq amount = new AmountReq();
        amount.setTotal((long) (order.getAmount() * 100));
        amount.setRefund((long) (refundAmount * 100));
        amount.setCurrency("CNY");
        refundRequest.setTransactionId(order.getOutTradeNo());
        refundRequest.setOutRefundNo(order.getOutTradeNo());
        refundRequest.setAmount(amount);
        refundRequest.setReason(reason);
        refundRequest.setNotifyUrl(configUtil.getString("wechat.pay.notify-url"));

        return refundService.create(refundRequest);
    }
}
